home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2003 #12 / Amiga Plus CD - 2003 - No. 12.iso / AmigaPlus / Scene / Magazine / Saxonia2 / articles / 047 < prev    next >
Text File  |  2003-05-10  |  14KB  |  316 lines

  1. Coding tutorial part 2
  2. by Rumrunner/VOID
  3. [l
  4.  
  5. Welcome back to this article series. This time, I will give a new example
  6. which will introduce some new instructions and show you how to display a
  7. copperlist on screen.
  8.  
  9. Right, let's take a look at the example code first and then I will comment
  10. everything below :[1 
  11.  
  12.     move.l    4.w,a6                ;execbase
  13.     lea.l    graphicsname(pc),a1        ;load adress into a1
  14.     jsr    -408(a6)            ;exacbase, openlibrary
  15.     move.l    d0,gfxbase            ;store graphic library base
  16.     move.l    d0,a0                ;copy gfxbase to a0
  17.     move.l    38(a0),savecopper        ;systemcopperlist found here
  18.     jsr    -132(a6)            ;stop multitasking
  19.  
  20.     move.l    #copperlist,$dff080        ;install own copperlist
  21. wait:
  22.     btst    #6,$bfe001            ;wellknown mousewait routine
  23.     bne.s    wait
  24.  
  25.     move.l    savecopper,$dff080        ;get back systemcopperlist
  26.  
  27.     move.l    gfxbase,a1            ;put gfxbase into register a1
  28.     jsr    -414(a6)            ;close graphics library
  29.     jsr    -138(a6)            ;enable multitasking again
  30.  
  31.     moveq    #0,d0                ;there are no errors
  32.     rts                    ;finished
  33.  
  34. gfxbase:
  35.     dc.l    0                ;space to store graphicsbase
  36.  
  37. savecopper:                    ;space to store copperlist
  38.     dc.l    0
  39.  
  40. graphicsname:                    ;name of library to open
  41.     dc.b    "graphics.library",0
  42.     even
  43.  
  44. **************
  45. * Copperlist *
  46. **************
  47.     section    needschip,data_c
  48.  
  49. copperlist:
  50.     dc.w    $100,0            ;no bitplanes
  51.     dc.w    $180,$329        ;colour register 0 (background)
  52.     dc.w    $6501,$fffe        ;wait for line 65 position 01
  53.     dc.w    $180,0            ;colour register 0 again
  54.     dc.w    $7501,$fffe        ;wait for line 75 position 01
  55.     dc.w    $180,$ff0        ;again background colour register
  56.     dc.l    -2            ;copperlist finished[0 
  57. [l
  58.  
  59. Right, that's all it takes for now, not that frightening. So let's start
  60. commenting what we do here.
  61.  
  62. [1
  63.     move.l    4.w,a6                ;execbase[0 
  64.  
  65. The move instruction can move data in various ways. What this particular
  66. instruction does is take the number that's located at memory adress 4 and
  67. put this value into the register a6. .l means that it takes a longword.
  68. A longword is 4 bytes (refer to the previous tutorial to learn about how
  69. bytes are built up. Another possibility is move.w which takes a word. A
  70. word is two bytes (half a longword). But as this is an adress, we need
  71. the whole longword. The .w in 4.w is a little trick for optimisation. What
  72. is basically does is only assemble 0004 into the instruction instead of
  73. 00000004, which means that we save two bytes. Don't worry about this for
  74. now, it will become clear in a while. Just remember that you can use this
  75. kind of adressing for "low" adresses, like 4, $6c and so on.
  76. [1 
  77.     lea.l    graphicsname(pc),a1        ;load adress into a1[0 
  78.  
  79. Lea is a command that loads a particular adress into a register. Here we
  80. load the adress where the name of the graphics.library is located into a1.
  81. Basically this means that if we look at the adress a1 now contains, we will
  82. find the string "graphics.library". The (pc) means that in this case,
  83. there's no need to store the whole adress in the code, we can use the
  84. program counter to find it. The program counter is the processor's register
  85. which it uses to find out where (in memory) it should execute the command
  86. from.
  87. [1 
  88.     jsr    -408(a6)            ;exacbase, openlibrary[0 
  89.  
  90. This is an easy one, however it is also somewhat diffucult. Let me start
  91. by saying that jsr jumps to the adress given and continues to execute the
  92. program from there. When it reached the rts command (which should be
  93. familiar), it continues below the point where the jsr was executed. Right
  94. now, we don't jump to a directly specified adress though, we jump to the
  95. adress 408 bytes below the content of a6. If you remember that we put the
  96. content of memory adress 4 into a6, this will soon become clear. The adress
  97. 4 is used by the operating system for the most important library on the
  98. Amiga, the exec.library. This library deals with allocating memory, opening
  99. and closing other libraries and other important stuff. So what we are
  100. working with here is really systemcode. -408 from execbase is the system
  101. function for opening a library. That's why we put the adress to the
  102. graphics.library string in a1, the openlibrary (-408) function in
  103. exec.library expects to find the adress of this string in register a1.
  104. There are some system functions that doesn't need any parameters, but for
  105. those who do, you always put the parameters in the given registers. These
  106. can be found for instance in the system programmer's manual.
  107. [1 
  108.     move.l    d0,gfxbase            ;store graphic library base[0 
  109.  
  110. Now, after executing the openlibrary function, that particular action
  111. gives us something interesting back in the d0 register. This is the
  112. graphics.library base. Just like exec, all registers have a baseadress,
  113. from which you can call functions. However, this is not why we open the
  114. library, but you will soon see why we do so. This is also another good
  115. example of a move command. We are still working with longwords, but now
  116. we take the value in d0 (the graphics.library base) and put it at a safe
  117. place in memory. If you read the previous tutorial and understood the part
  118. about labels, you will recognise this, as we now store something into the
  119. memory a label represents instead of jumping there.
  120. [1 
  121.     move.l    d0,a0                ;copy gfxbase to a0[0 
  122.  
  123. This is yet another example of the move command. This is the simples one,
  124. we move the content of d0 (still the graphics.library base) into a0. This
  125. because adress registers have some possibilities dataregisters don't have.
  126. You will see it in the next instruction.
  127. [1 
  128.     move.l    38(a0),savecopper        ;systemcopperlist found here[0 
  129.  
  130. Now, we are talking. This is one of the most important tasks you can
  131. perform with the move command. I guess that it's clear that we store
  132. something at the label savecopper, but what we store is perhaps not so
  133. clear. What 38(a0) means is that we don't want to store anything that has
  134. to do with the content of a0. What we want to store is the value located
  135. 38 bytes above the adress that a0 is pointing to. I will illustrate this
  136. here :
  137.  
  138. Let's say that a0 is $40000. Now, while the command  move.l a0,savecopper
  139. would store the value $40000, we now want to store the content of adress
  140. $40038. If the value located at $40038 is $3ff0, then savecopper will now
  141. contain the value $3ff0. You can think a little about the jsr command we
  142. have taken a look at, as it is the same kind of adressing. Also take a look
  143. at the first command (move.l 4.w,a6). We want the content of adress 4 and
  144. not the number 4, this is also the case here.
  145. [1 
  146.     jsr    -132(a6)            ;stop multitasking[0 
  147.  
  148. Here, it's time for yet another system call. Execbase stops multitasking
  149. when you jump to -132(execbase), so let's do that in order to not interfere
  150. too much with other running programs.
  151. [1 
  152.     move.l    #copperlist,$dff080        ;install own copperlist[0 
  153.  
  154. Another move again. Hopefully, you will now understand that this is an
  155. important instruction. You will certainly use it a lot. What we do here
  156. is to take the adress of the adress copperlist: and put this into the
  157. register $dff080, which by the way is called cop1lch. It's here that the
  158. Amiga finds out where the copperlist is located.
  159. A little help now, some people might already have found this out, but here
  160. we go. We want the adress of the copperlist right? Yes, so we could also
  161. have used :
  162.  
  163.     lea.l    copperlist,a0
  164.     move.l    a0,$dff080
  165.  
  166. Refer to the notes about the lea instruction of this seems strange.
  167. However, as the copperlist is in another section (remember those from
  168. last time?) we cannot use the optimising method (pc) in order to shorten
  169. the program and get a little faster execution.
  170. By the way, it's time to tell a little about the hardware registers. They
  171. are located from the adress $dff000 to $dffffe, however not all are used.
  172. The best way of getting to know these is to get a copy of the hardware
  173. reference manual. You will need this as registers have several ways of
  174. working. The cop1lch register is easy because you only need to feed it
  175. with an adress. Other register however, have certain functions connected
  176. to each bit and works in special ways (which we will come back to in the
  177. next tutorial), so an overview on paper is very good.
  178.  
  179.  
  180. The next part of the code is the famous mousewait routine from last time,
  181. so there's no need to comment that again.
  182. [1 
  183.     move.l    savecopper,$dff080        ;get back systemcopperlist[0 
  184.  
  185. Right, when the user presses the mousebutton, we want to get the system
  186. back on track. What we need to do is to put back the copperlist we found
  187. 38 bytes over execbase. So, we simply write it to $dff080. This also shows
  188. yet another way of using the move instrucion. We now move the value located
  189. in memory adress the savecopper label is pointing to into $dff080. If we
  190. tried  move.l #savecopper,$dff080, we would move the adress where the label
  191. was into $dff080 and not what it was pointing to. This is a bit confusing
  192. in the start, but it will quickly clear out.
  193. [1 
  194.     move.l    gfxbase,a1            ;gfxbase into register a1 [0 
  195.  
  196. We stored the graphics.library base earlier, so let's move it into a1,
  197. because that's where the exec.library expects it when you want to close
  198. graphics.library again.
  199.  
  200. [1 
  201.     jsr    -414(a6)            ;close graphics library[0 
  202.  
  203. So, again an exec.library function. It simply closes the graphics.library.
  204. [1 
  205.     jsr    -138(a6)            ;enable multitasking again[0 
  206.  
  207. We stopped multitasking earlier, -138(execbase) enables multitasking again.
  208. [1 
  209.     moveq    #0,d0                ;there are no errors[0 
  210.  
  211. Moveq is a special kind of move. It is faster than the original move but
  212. can only be used on numbers which can be represented with a few bits only.
  213. It doesn't matter however, where these bits are set. When exiting a program,
  214. a zero in d0 means that there are no errors. So the system will not put
  215. up an error message. If you want to try to make an error however, you need
  216. to run your program from a script (like the startup-sequence) as it doesn't
  217. show when run directly from CLI.
  218. [1 
  219.     rts                    ;finished[0 
  220.  
  221. Finally, we have reached the end of the program. There is some more to
  222. comment though.
  223.  
  224. [1 
  225. savecopper:                    ;space to store copperlist
  226.     dc.l    0[0 
  227.  
  228. Just like last time, this is a label. It's no code at this memory location
  229. this time however, we just want to have a place to store a longword.
  230. dc.l simply means declare longword, in other words we put a longword of
  231. zero at the location. You can use dc.l 4598 or whatever if you want to
  232. as the content will be replaced when we do a move.l to the location.
  233.  
  234. The graphicsname label also shows that you can put ascii numbers into
  235. memory. We use dc.b since one character uses one byte, so longword would
  236. be meaningless here. The "" signs tells that it is ascii-values we want,
  237. the assembler replaces these with the correct bytes for us.
  238.  
  239. Now, we have come to the interesting part, the copperlist. The copper is
  240. one of the Amiga's most unique features, until the Commodore One (which
  241. sound really exciting read separate article) arrived, the Amiga was the
  242. only computer who could have several resolutions on screen at once. And
  243. since the Commodore One is a kind of special interest computer, just like
  244. the Amiga has become, Amiga is still the only widely used computer ever
  245. which has had this possibility.
  246.  
  247. Now, how can the copper do such magic? Well, the principle is simple,
  248. however, the workings is a little hard to cath at first.
  249.  
  250. The copper has three functions and the two most important ones are move
  251. and wait. Move moves a value into the adress specified. The wait command
  252. stops execution until the screen is drawn at the specified waiting
  253. position. In the copperlist in our program, we can see examples of both
  254. commands. It's important to remember that every adress we write to is
  255. written in words, not longwords, as the copper is a wordprocessor, or to
  256. avoid confusion, it processes words as in two bytes. However, when we
  257. write to $180, we really write to $dff180 (remember hardware registers?).
  258. So we can only write to hardware registers using the copper but those are
  259. the only ones of interest here, so that's not a problem.
  260.  
  261. A move is carried out in the following way. Note that most assemblers
  262. doesn't support copper instructions, so we have to use dc.w (declare word) :
  263.  
  264.     dc.w    $hardwareregister,$value
  265.  
  266. example:
  267.     dc.w    $180,$0
  268.  
  269. $dff180 is the background colour register, and it will here get the
  270. value zero, which means black screen. When we write to $dff100 in the
  271. program's copperlist, this is the bplcon0 register, which we need to
  272. set up bitplanes to get images on screen.
  273.  
  274. The wait command is carried out this way :
  275.  
  276.     dc.w    waitposition,$fffe
  277.  
  278. example:
  279.     dc.w    $6501,$fffe
  280.  
  281. Try to change the values written to $180 and the waits in the program
  282. copperlist and you will soon find out how it works. There are some things
  283. you need to know about waitpositions first though. First of all, the
  284. first byte (in this example $65) is the vertical position and the next
  285. byte ($01) is the horisontal position. You can wait for all vertical
  286. positions, but the horisontal positions need to be odd, like 1,3,5 and so
  287. on. Next, the screens doesn't start at vertical $00, it starts at about
  288. $20,$30. If you try values like this in the copperlist, you will see that
  289. way on top of the screen, the colourchange occurs. Then, the bottom of
  290. the screen (the PAL area) starts at zero. So, let's illustrate
  291.  
  292.           ____________________
  293.    ---/  |                    | Ntsc part
  294.    |     |                    |
  295.    | s   |                    |$30 to $ff
  296.    | c   |                    |
  297.    | r   |                    |
  298.    | e   |                    |
  299.    | e   |                    |-------
  300.    | n   |                    |Pal part
  301.    |     |                    |$01 to $30
  302.    |     |                    |
  303.    ---\  |____________________|
  304.  
  305.  
  306. With some possible difference on ntsc start and pal stop.
  307.  
  308. How to use the palscreen, I will come back to later, but for now, have
  309. fun with the example code, it's included on the disk so you won't have
  310. to type everything in. Try altering parts when you figure out what it
  311. does and see what happens. Not just in the copperlist, but in the code
  312. like I suggested (remember the move.l #copperlist.....).
  313.  
  314. And good luck.
  315.